JS实现公告消息滚动

因为要适配iOS前端,所以在想最简实现一个静态数据的抽奖滚动栏,研究时直接用了当前运行的ReactJS框架实现,于是昨天先打了个草稿。经测试在iPhone6S Plus A1699 Version 12.1.2上显示正常。

import React from 'react'
 
class ScrollMessagePage {
 
    componentDidMount() {
        //消息关键字数据
        const loanUserList = ['赵', '钱', '孙', '宋', '王', '徐', '丘', '骆', '高', '夏', '蔡', '田', '樊', '胡', '陈', '霍', '潘', '万', '李', '洪', '莫', '王']
        const loanMoneyList = [10, 12, 8, 5, 8, 7, 6, 23, 18, 10, 2, 1]
        const loanSexList = ['先生', '先生', '先生', '女士', '女士']
 
        function getText() {
            const randomSex = loanSexList[parseInt(Math.random() * loanSexList.length)]
            const randomName = loanUserList[parseInt(Math.random() * loanUserList.length)]
            const randomMoney = loanMoneyList[parseInt(Math.random() * loanMoneyList.length)]
            return randomName + randomSex + '获得' + randomMoney + '元红包'
        }
 
        let messageList = []
        for (let i = 0; i < 3; i++) {
            messageList.push(getText())
        }
        let box = document.getElementById('scroll-message')
        box.style.height = '30px'
        box.style.overflow = 'hidden'
 
        function createElement(text) {
            let Text = document.createElement('div')
            Text.style.height = '30px'
            Text.style.transition = 'margin-top 1s'
            Text.innerText = text
            box.appendChild(Text)
        }
 
        messageList.map(text => {
            createElement(text)
        })
        this.timer = setInterval(() => {
            createElement(getText())
            box.childNodes[1].style.marginTop = '-30px'
            box.removeChild(box.childNodes[0])
        }, 3000)
    }
 
    componentWillUnMount() {
        clearInterval(this.timer)
    }
 
    render() {
        return (
            <div className="match">
                <div id="scroll-message"/>
            </div>
        )
    }
 
 
}
 
export default ScrollMessagePage

经过今天的测试发现,在第一次加载计时器的时候滚动条会将滚动数据第二条数据快速跳过,造成不好的用户体验,于是使用了文档碎片对滚动条进行优化

        let box = document.getElementById('scroll-message')
        let fragement = document.createDocumentFragment('div')
        let message = document.createElement('div')
        message.style.height = '30px'
        message.style.overflow = 'hidden'
        fragement.appendChild(message)

        function createElement(text, style, ele = message) {
            let Text = document.createElement('div')
            Text.style.height = '30px'
            Text.style.lineHeight = '30px'
            Text.style.transition = 'margin-top 1s'
            style && Object.keys(style).map(key => Text.style[key] = style[key])
            Text.innerText = text
            ele.appendChild(Text)
        }

        let messageList = []
        for (let i = 0; i < 2; i++) {
            messageList.push(getText())
        }
        messageList.map((text, index) => createElement(text, index===0?{marginTop:'-30px'}:null))
        this.timer = setInterval(() => {
            createElement(getText())
            message.childNodes[1].style.marginTop = '-30px'
            message.removeChild(message.childNodes[0])
        }, 3000)
        box.appendChild(fragement)

【如何修复数据跳过BUG】此次更新修复了滚动条在第一次计时器运行时跳过第二条数据的问题,发生问题的原因是因为初始化公告栏数据的时候并未添加marginTop,在计时器执行之后第二条数据原本会替换第一条数据的位置,然而因为第一条数据被删除所以跑到第一条数据位置上面,我通过直接将第二条数据初始化到第一条数据的位置解决了该问题。

【处理性能损耗】频繁对dom进行操作,会使整个页面频繁进行DOM渲染,解决性能损耗的问题我参考 createDocumentFragment();方法实现,将该公告栏DOM插入到该方法创建的文档碎片,将子元素插入到文档片段时不会引起页面回流。

小结

初次向大家分享我的想法,有更好的实现方法可以评论留言,关于性能损耗的问题我认识有些不足,请大家多多指教。

泉州牧码人
73 声望4 粉丝

前端工程师